package br.boicotando.client;

import java.util.Date;
import java.util.List;

import br.boicotando.dominio.Cliente;
import br.boicotando.dominio.Setor;
import br.boicotando.shared.Util;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBoxBase;
import com.google.gwt.user.client.ui.VerticalPanel;

public class Boicotando implements EntryPoint {
	
	private static final GerenciadorLojaAsync gerenciadorLoja = GWT.create(GerenciadorLoja.class);
	private static final GerenciadorClienteAsync gerenciadorCliente = GWT.create(GerenciadorCliente.class);
	private static final VerticalPanel vpanel = new VerticalPanel();
	private static final HorizontalPanel cabecalhoPanel = new HorizontalPanel();
	private static final HTML logotipo = new HTML("<table><tr><td><img src='/boicotando/imagens/boicotando.jpg' height='80'/></td><td><h1>BoiCotando $-))</h1><b><i>Seu site de compras na internet.</i></b></td></tr></table>");
	private static final VerticalPanel usuarioPanel = new VerticalPanel(); 
	private static final VerticalPanel panel = new VerticalPanel();
	
	public static final KeyPressHandler KEY_PRESS_HANDLER_VALIDA_NUMERO = new KeyPressHandler() {
		@Override
		public void onKeyPress(KeyPressEvent event) {
			if (event.getUnicodeCharCode() > 0 && (event.getCharCode() < '0' || event.getCharCode() > '9')) {
				TextBoxBase texto = (TextBoxBase) event.getSource();
				texto.cancelKey();
			}
		}
	};
	
	public static final ChangeHandler CHANGE_HANDLER_VALIDA_CPF = new ChangeHandler() {
		@Override
		public void onChange(ChangeEvent event) {
			TextBoxBase texto = (TextBoxBase) event.getSource();
			
			if (texto.getValue() != null && !texto.getValue().isEmpty()) {
				char chars[] = {'.', '-'};
		        String valor = Util.strRemove(texto.getValue(), chars);
		        int     d1, d2;
		        int     digito1, digito2, resto;
		        int     digitoCPF;
		        d1 = d2 = 0;
		        digito1 = digito2 = resto = 0;
		        for (int i = 1; i < valor.length() -1; i++) {
		            digitoCPF = Integer.valueOf (valor.substring(i -1, i)).intValue();
		            d1 = d1 + ( 11 - i ) * digitoCPF;
		            d2 = d2 + ( 12 - i ) * digitoCPF;
		        }
		        resto = (d1 % 11);
		        if (resto < 2) { 
		            digito1 = 0;
		        } else {
		            digito1 = 11 - resto;
		        }
		        d2 += 2 * digito1;
		        resto = (d2 % 11);
		        if (resto < 2) {
		            digito2 = 0;
		        } else {
		            digito2 = 11 - resto;
		        }
		        String digito = valor.substring (valor.length()-2, valor.length());
		        String digitoCalculado = String.valueOf(digito1) + String.valueOf(digito2);
		        if (digito.equals(digitoCalculado)) {
		            texto.setValue(Util.strFormata(valor, "000.000.000-00") );
		        } else {
		            Window.alert("CPF inválido, verifique!");
		            texto.setFocus(true);
		        }				
			}
		}		
	};

	public static class CaixaData extends Composite {
		private int anoInicial;
		private int anoFinal;
		private final HorizontalPanel panel = new HorizontalPanel();
		private final ListBox diaListBox = new ListBox();
		private final ListBox mesListBox = new ListBox();
		private final ListBox anoListBox = new ListBox();
			
		private boolean adicionaDias(int diaLimite) {
			boolean adicionou = false;
			for (int dia = diaListBox.getItemCount() - 1; dia < diaLimite; dia = diaListBox.getItemCount() - 1) {
				diaListBox.addItem(Integer.toString(dia + 1), Integer.toString(dia + 1));
				adicionou = true;
			}
			return adicionou;
		}
		
		private boolean removeDias(int diaLimite) {
			boolean removeu = false;
			if (diaListBox.getSelectedIndex() > diaLimite) {
				diaListBox.setSelectedIndex(0);
			}
			for (int i = diaListBox.getItemCount() - 1; i > diaLimite; --i) {
				diaListBox.removeItem(i);
				removeu = true;
			}
			return removeu;
		}

		private void listaDias() {
			String mes = mesListBox.getValue(mesListBox.getSelectedIndex());
			int ano = getAno();
			
			if (diaListBox.getItemCount() == 0) { 
				diaListBox.addItem("Dia:", "0");
			}
			
			if (! mes.equals("|fev|") || (ano != 0 && Util.anoEhBissesto(ano))) {
				if (mes.equals("|fev|")) {
					if (!adicionaDias(29)) {
						removeDias(29);
					}
				} else {
					if ("|nil|jan|mar|mai|jul|ago|out|dez|".indexOf(mes) >= 0) {
						adicionaDias(31);
					} else {
						if (! adicionaDias(30)) {
							removeDias(30);
						}
					}
				}
			} else {
				if (! adicionaDias(28)) {
					removeDias(28);
				}
			}
		}
		
		private void listaMeses() {
			mesListBox.clear();
			mesListBox.addItem("Mês:", "|nil|");
			mesListBox.addItem("Janeiro", "|jan|");
			mesListBox.addItem("Fevereiro", "|fev|");
			mesListBox.addItem("Março", "|mar|");
			mesListBox.addItem("Abril", "|abr|");
			mesListBox.addItem("Maio", "|mai|");
			mesListBox.addItem("Junho", "|jun|");
			mesListBox.addItem("Julho", "|jul|");
			mesListBox.addItem("Agosto", "|ago|");
			mesListBox.addItem("Setembro", "|set|");
			mesListBox.addItem("Outubro", "|out|");
			mesListBox.addItem("Novembro", "|nov|");
			mesListBox.addItem("Dezembro", "|dez|");
		}
		
		private void listaAnos() {
			anoListBox.clear();
			anoListBox.addItem("Ano:", "|nil|");
			for (int ano = anoInicial; ano <= anoFinal; ++ano) {
				anoListBox.addItem(Integer.toString(ano), Integer.toString(ano));
			}				
		}

		
		public CaixaData(int fatorAnoInicial, int fatorAnoFinal) {
			Date hoje = new Date();
			DateTimeFormat format = DateTimeFormat.getFormat("y");
			int ano = Integer.parseInt(format.format(hoje));
			anoInicial = ano + fatorAnoInicial;
			anoFinal = ano + fatorAnoFinal;
			
			listaAnos();
			listaMeses();
			listaDias();
			
			mesListBox.addChangeHandler(new ChangeHandler() {
				@Override
				public void onChange(ChangeEvent event) {
					listaDias();
				}
			});
			
			anoListBox.addChangeHandler(new ChangeHandler() {
				@Override
				public void onChange(ChangeEvent event) {
					listaDias();
				}
			});

			panel.add(diaListBox);
			panel.add(mesListBox);
			panel.add(anoListBox);
			
			initWidget(panel);
		}
		
		
		public int getAno() {
			int ano = anoInicial + anoListBox.getSelectedIndex() - 1;
			return (ano < anoInicial) ? 0 : ano;
		}
		
		public int getAnoInicial() {
			return anoInicial;
		}
		
		public int getAnoFinal() {
			return anoFinal;
		}
		
		public int getMes() {
			return mesListBox.getSelectedIndex();
		}
		
		public int getDia() {
			return diaListBox.getSelectedIndex();
		}
		
		public Date getValor() {
			Date data = null;
			if (diaListBox.getSelectedIndex() != 0 && mesListBox.getSelectedIndex() != 0 && anoListBox.getSelectedIndex() != 0) {
				NumberFormat formater = NumberFormat.getFormat("00");
				DateTimeFormat dateFormater = DateTimeFormat.getFormat("dd'/'MM'/'y");
				StringBuffer sb = new StringBuffer();
				sb.append(formater.format(diaListBox.getSelectedIndex()));
				sb.append('/');
				sb.append(formater.format(mesListBox.getSelectedIndex()));
				sb.append('/');
				sb.append(anoInicial + anoListBox.getSelectedIndex() - 1);
				data = dateFormater.parse(sb.toString());
			}
			return data;
		}
		
		public void setValor(Date data) {
			if (data == null) {
				listaAnos();
				listaMeses();
				listaDias();
			} else {
				int ano = Integer.parseInt(DateTimeFormat.getFormat("y").format(data));
				if (ano < anoInicial || ano > anoFinal) {
					anoListBox.setSelectedIndex(0);
				} else {
					anoListBox.setSelectedIndex(ano - anoInicial + 1); 
				}
				mesListBox.setSelectedIndex(Integer.parseInt(DateTimeFormat.getFormat("M").format(data)));
				listaDias();
				diaListBox.setSelectedIndex(Integer.parseInt(DateTimeFormat.getFormat("d").format(data)));
			}
		}
		
	}
	
	public static enum Tela {
		SELECAO_PRODUTO,
		CADASTRO_CLIENTE,
		CADASTRO_DADOS_ENTREGA
	}
	
	public void onModuleLoad() {
		cabecalhoPanel.setWidth("100%");
		panel.setWidth("100%");
		vpanel.setWidth("100%");
		exibeTela(Tela.SELECAO_PRODUTO);
	}
	
	public static void exibeTela(Tela tela) {
		RootPanel.get().clear();
		vpanel.clear();
		panel.clear();
		
		cabecalhoPanel.clear();
		cabecalhoPanel.add(logotipo);
		cabecalhoPanel.add(usuarioPanel);
		cabecalhoPanel.setCellHorizontalAlignment(usuarioPanel, HasHorizontalAlignment.ALIGN_RIGHT);
		cabecalhoPanel.setStyleName("formulario", true);
		vpanel.add(cabecalhoPanel);
		vpanel.add(panel);

		gerenciadorCliente.getUsuarioAtivo(new AsyncCallback<Cliente>() {
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Não foi possivel verificar o usuário ativo:" + caught.getMessage());
			}
			
			@Override
			public void onSuccess(Cliente cliente) {
				Button cadastroButton = new Button(), sairButton;

				usuarioPanel.clear();

				cadastroButton.addClickHandler(new ClickHandler() {
					@Override
					public void onClick(ClickEvent event) {
						exibeTela(Tela.CADASTRO_CLIENTE);
					}
				});
				
				if (cliente == null) {
					cadastroButton.setText("Faça seu login ou cadastre-se");
					usuarioPanel.add(new HTML("<b><i>Seja bem vindo!</i></b>"));
					usuarioPanel.add(cadastroButton);	
				} else {
					sairButton = new Button("Sair");
					sairButton.addClickHandler(new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							gerenciadorCliente.logoff(new AsyncCallback<Void>() {
								@Override
								public void onFailure(Throwable caught) {
									Window.alert("Não foi possível fazer o logoff: "+ caught.getMessage());
								}

								@Override
								public void onSuccess(Void result) {
									exibeTela(Tela.SELECAO_PRODUTO);
								}
							});
						}
					});
					cadastroButton.setText("Atualize seu cadastro");
					usuarioPanel.add(new HTML("<b><i>Olá, " + cliente.getNome() + ". Boas Compras!</i></b>"));					
					usuarioPanel.add(cadastroButton);
					usuarioPanel.add(sairButton);
				}
			}
		});
		
		if (tela == Tela.SELECAO_PRODUTO) {
			HTML tituloHTML = new HTML("<h2>Seleção de Produtos</h2>");
			tituloHTML.setStyleName("titulo", true);
			panel.add(tituloHTML);
			
			gerenciadorLoja.consultarSetores(new AsyncCallback<List<Setor>>() {
				@Override
				public void onFailure(Throwable caught) {
					Window.alert("A consulta de setores falhou: " + caught.getMessage());				}
				
				@Override
				public void onSuccess(List<Setor> setores) {
					panel.add(new TelaSelecaoProduto(setores));
				}		
			});
		} else if (tela == Tela.CADASTRO_CLIENTE) {
			HTML tituloHTML = new HTML("<h2>Identificação</h2>");
			tituloHTML.setStyleName("titulo", true);
			panel.add(tituloHTML);
			panel.add(new TelaCadastroCliente());
		} else if (tela == Tela.CADASTRO_DADOS_ENTREGA) {
			HTML tituloHTML = new HTML("<h2>Dados de entrega</h2>");
			tituloHTML.setStyleName("titulo", true);
			panel.add(tituloHTML);
			panel.add(new TelaCadastroCliente());
		}

		RootPanel.get().add(vpanel);
	}
}